package com.example.opengldemo.vertex_magical.shader;

import android.content.res.Resources;
import android.opengl.GLES30;

import com.example.opengldemo._camera_demo.buffer.FrameBuffer;
import com.example.opengldemo.util.MatrixState;
import com.example.opengldemo.util.ShaderBuffer;
import com.example.opengldemo.util.ShaderHandle;
import com.example.opengldemo.util.ShaderUtil;
import com.example.opengldemo.vertex_magical.core.FrameRenderer;

import java.util.LinkedList;

public class ShakeShader implements FrameRenderer {

    private ShaderHandle shaderHandle ;
    private ShaderBuffer shaderBuffer ;
    private FrameBuffer frameBuffer ;

    protected Resources res ;
    protected String vertex ;
    protected String fragment ;

    private int mGLWidth;
    private int mGLHeight;
    protected int mWidth;
    protected int mHeight;

    private final LinkedList<Runnable> mTasks=new LinkedList<>();
    private final Object Lock = new Object();

    final float WIDTH_SPAN=3.3f;
    float currStartAngle=0;

    protected ShakeShader(Resources resource, String vertex, String fragment) {
        this.res  =resource  ;
        this.vertex  =vertex  ;
        this.fragment  =fragment  ;

    }


    public void onInit() {
        shaderBuffer = new ShaderBuffer() ;
        frameBuffer = new FrameBuffer() ;
        final int cols=12;
        final int rows=cols*3/4;
        shaderBuffer.setVertexBuffer(initVertexData(cols, rows));
        shaderBuffer.setTexcoorBuffer(generateTexCoor(cols, rows));

    }
    public static boolean threadFlag = true ;
    @Override
    public void create() {
        onInit();
        if(shaderHandle != null){
            onCreate();
        }
    }

    protected void onCreate() {
        if(this.res == null){
            shaderHandle = new ShaderHandle(ShaderUtil.createProgram(this.vertex,this.fragment)) ;
        }else{
            this.vertex = ShaderUtil.loadFromAssetsFile(this.vertex, this.res);
            this.fragment = ShaderUtil.loadFromAssetsFile(this.fragment, this.res);
            shaderHandle = new ShaderHandle(ShaderUtil.createProgram(this.vertex,this.fragment)) ;
        }

        int uStartAngle = shaderHandle.getUHandle("uStartAngle");
        int uWidthSpan = shaderHandle.getUHandle("uWidthSpan");
        shaderHandle.UHandleArray[0] = uStartAngle;
        shaderHandle.UHandleArray[1] = uWidthSpan;

        MatrixState.setInitStack();
        new Thread()
        {
            public void run()
            {
                while(threadFlag)
                {
                    currStartAngle+=(float) (Math.PI/16);
                    try
                    {
                        Thread.sleep(50);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    }

    @Override
    public void sizeChanged(int width, int height) {
        this.mWidth=width;
        this.mHeight=height;
        onSizeChanged(width, height);
        frameBuffer.destroyFrameBuffer();
    }

    protected void onSizeChanged(int width, int height) {
        float ratio = (float) width / height ;

    }

    public int drawToTexture(int texture){
        frameBuffer.bindFrameBuffer(mWidth,mHeight);
        draw(texture);
        frameBuffer.unBindFrameBuffer();
        return frameBuffer.getCacheTextureId();
    }
    @Override
    public void draw(int texture) {
        onClear();
        onUseProgram();
        onSetExpandData();
        onBindTexture(texture);
        onDraw();
    }
    protected void onClear(){
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
    }
    protected void onUseProgram(){
        shaderHandle.program() ;
        onTaskExec();
    }
    protected void onTaskExec(){
        synchronized (Lock) {
            while (!mTasks.isEmpty()){
                mTasks.removeFirst().run();
            }
        }
    }
    /**
     * 设置其他扩展数据 静态uniform类型
     */
    protected void onSetExpandData(){
        shaderHandle.bindMVPMaxtrixHandle(MatrixState.getMMatrix());
        GLES30.glUniform1f(shaderHandle.UHandleArray[0] ,currStartAngle );
        GLES30.glUniform1f(shaderHandle.UHandleArray[2] ,WIDTH_SPAN );
        shaderHandle.bindVertexHandle(shaderBuffer.getVertexBuffer()) ;
        shaderHandle.bindTexCoorsHandle(shaderBuffer.getTexcoorBuffer());
    }
    /**
     * 绑定纹理
     */
    protected void onBindTexture(int textureId){
        shaderHandle.bindDefaultTextureHandle(textureId) ;
    }

    /**
     * 绑定动态 in 数据即绘制
     */
    protected void onDraw(){
        shaderHandle.run(GLES30.GL_TRIANGLES, shaderBuffer.vCount);
    }


    @Override
    public void destroy() {
        frameBuffer.destroyFrameBuffer();
        shaderHandle.destroy();
    }

    public float[] initVertexData(int cols , int rows) {

        final float UNIT_SIZE=WIDTH_SPAN/cols;

        int vcont=cols*rows*6;
        float vertices[]=new float[vcont*3];
        int count=0;
        for(int j=0;j<rows;j++)
        {
            for(int i=0;i<cols;i++)
            {
                float zsx=-UNIT_SIZE*cols/2+i*UNIT_SIZE;
                float zsy=UNIT_SIZE*rows/2-j*UNIT_SIZE;
                float zsz=0;

                vertices[count++]=zsx;
                vertices[count++]=zsy;
                vertices[count++]=zsz;

                vertices[count++]=zsx;
                vertices[count++]=zsy-UNIT_SIZE;
                vertices[count++]=zsz;

                vertices[count++]=zsx+UNIT_SIZE;
                vertices[count++]=zsy;
                vertices[count++]=zsz;

                vertices[count++]=zsx+UNIT_SIZE;
                vertices[count++]=zsy;
                vertices[count++]=zsz;

                vertices[count++]=zsx;
                vertices[count++]=zsy-UNIT_SIZE;
                vertices[count++]=zsz;

                vertices[count++]=zsx+UNIT_SIZE;
                vertices[count++]=zsy-UNIT_SIZE;
                vertices[count++]=zsz;
            }
        }
        return vertices ;


    }
    public float[] generateTexCoor(int bw,int bh) {
        float[] result=new float[bw*bh*6*2];
        float sizew=1.0f/bw;
        float sizeh=0.75f/bh;
        int c=0;
        for(int i=0;i<bh;i++)
        {
            for(int j=0;j<bw;j++)
            {
                float s=j*sizew;
                float t=i*sizeh;

                result[c++]=s;
                result[c++]=t;

                result[c++]=s;
                result[c++]=t+sizeh;

                result[c++]=s+sizew;
                result[c++]=t;


                result[c++]=s+sizew;
                result[c++]=t;

                result[c++]=s;
                result[c++]=t+sizeh;

                result[c++]=s+sizew;
                result[c++]=t+sizeh;
            }
        }
        return result;
    }


}
